/**
 * @addtogroup FXGE
 * @{
 */

/**
 * @file
 * @brief Device Independent Bitmap (DIB) Processing Engine.
 */
//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FX_DIB565_H_
#define _FX_DIB565_H_
//<<<+++OPENSOURCE_MUST_END

#include "fx_dib.h"
inline void _Set2RGB565(FX_LPBYTE dst, FX_BYTE r, FX_BYTE g, FX_BYTE b)
{
	dst[0] = (r >> 3) | ((g & 0xfc) << 3);
	dst[1] = ((g & 0xfc) >> 5) | (b & 0xf8);
}

inline void _Set2BGR565(FX_LPBYTE dst, FX_BYTE r, FX_BYTE g, FX_BYTE b)
{
	dst[0] = (b >> 3) | ((g & 0xfc) << 3);
	dst[1] = ((g & 0xfc) >> 5) | (r & 0xf8);
}

inline void _SetBGR2RGB565(FX_LPBYTE dst, FX_LPCBYTE bgr)
{
	_Set2RGB565(dst, bgr[2], bgr[1], bgr[0]);
}
inline void _SetBGR2BGR565(FX_LPBYTE dst, FX_LPCBYTE bgr)
{
	_Set2BGR565(dst, bgr[2], bgr[1], bgr[0]);
}
inline void _SetRGB5652RGB(FX_LPBYTE dest, FX_LPCBYTE src) {
	FX_WORD pixel = *(FX_WORD*)src;
	*dest++ = (pixel & 0xf800) >> 8;
	*dest++ = (pixel & 0x7e0) >> 3;
    *dest++ = (pixel & 0x1f) << 3;
}
inline void _SetBGR5652RGB(FX_LPBYTE dest, FX_LPCBYTE src) {
	FX_WORD pixel = *(FX_WORD*)src;
	*dest++ = (pixel & 0x1f) << 3;
	*dest++ = (pixel & 0x7e0) >> 3;
    *dest++ = (pixel & 0xf800) >> 8;

}

inline void _SetBGRA2RGB565(FX_LPBYTE dst, FX_LPCBYTE bgra)
{
	FX_BYTE dst_bgr[3];
	_SetRGB5652RGB(dst_bgr, dst);
	FX_BYTE b = FXDIB_ALPHA_MERGE(dst_bgr[0], bgra[0], bgra[3]);
	FX_BYTE g = FXDIB_ALPHA_MERGE(dst_bgr[1], bgra[1], bgra[3]);
	FX_BYTE r = FXDIB_ALPHA_MERGE(dst_bgr[2], bgra[2], bgra[3]);
	_Set2RGB565(dst, r, g, b);
}

inline void _SetBGRA2BGR565(FX_LPBYTE dst, FX_LPCBYTE bgra)
{
	FX_BYTE dst_bgr[3];
	_SetBGR5652RGB(dst_bgr, dst);
	FX_BYTE b = FXDIB_ALPHA_MERGE(dst_bgr[0], bgra[0], bgra[3]);
	FX_BYTE g = FXDIB_ALPHA_MERGE(dst_bgr[1], bgra[1], bgra[3]);
	FX_BYTE r = FXDIB_ALPHA_MERGE(dst_bgr[2], bgra[2], bgra[3]);
	_Set2BGR565(dst, r, g, b);
}

inline void _SetRGB5652RGB32(FX_LPBYTE dest, FX_LPCBYTE src) {
	_SetRGB5652RGB(dest, src);
}

inline void _SetBGR5652RGB32(FX_LPBYTE dest, FX_LPCBYTE src) {
	_SetBGR5652RGB(dest, src);
}

class CFX_DIBitmap565 : public CFX_Object
{
public:
	CFX_DIBitmap565();
	virtual			~CFX_DIBitmap565();
	FX_BOOL			Create(int width, int height, FX_LPBYTE pBuffer = NULL, int pitch = 0);

	int				GetWidth() const { return m_Width; }
	int				GetHeight() const { return m_Height; }
	FX_DWORD		GetPitch() const { return m_Pitch; }
	int				GetBPP() const { return m_bpp; }

	FX_LPBYTE		GetBuffer() const { return m_pBuffer; }
	FX_LPCBYTE		GetScanline(int line) const { return m_pBuffer ? m_pBuffer + line * m_Pitch : NULL; }

	FX_BOOL			CompositeBitmap(int dest_left, int dest_top, int width, int height, 
								const CFX_DIBSource* pSrcBitmap, int src_left, int src_top, 
								int blend_type = FXDIB_BLEND_NORMAL, const CFX_ClipRgn* pClipRgn = NULL, FX_BOOL bRgbByteOrder = FALSE, void* pIccTransform = NULL);
	FX_BOOL			CompositeMask(int dest_left, int dest_top, int width, int height, 
								const CFX_DIBSource* pMask, FX_DWORD color, int src_left, int src_top,
								int blend_type = FXDIB_BLEND_NORMAL, const CFX_ClipRgn* pClipRgn = NULL, FX_BOOL bRgbByteOrder = FALSE, int alpha_flag = 0, void* pIccTransform = NULL);
	FX_BOOL			CompositeRect(int dest_left, int dest_top, int width, int height, FX_DWORD color, FX_BOOL bRgbByteOrder = FALSE, int alpha_flag = 0, void* pIccTransform = NULL);
	CFX_DIBitmap565*SwapXY(FX_BOOL bXFlip, FX_BOOL bYFlip, const FX_RECT* pClip = NULL) const;

	void			GetOverlapRect(int& dest_left, int& dest_top, int& width, int& height, int src_width, 
								int src_height, int& src_left, int& src_top, const CFX_ClipRgn* pClipRgn);
protected:
	CFX_DIBitmap565(const CFX_DIBitmap565& src);
	

	int				m_Width;
	int				m_Height;
	int				m_bpp;
	FX_DWORD		m_Pitch;
	FX_LPBYTE		m_pBuffer;
	FX_BOOL			m_bExtBuf;
};

class CFX_DIBSourceTranslate : public CFX_DIBSource
{
public:
	CFX_DIBSourceTranslate();
	virtual				~CFX_DIBSourceTranslate();
	FX_BOOL				Create(CFX_DIBitmap565* pBitmap565, FXDIB_Format dest_format);
	
	virtual FX_LPCBYTE	GetScanline(int line) const;
	virtual void		DownSampleScanline(int line, FX_LPBYTE dest_scan, int dest_bpp,
										int dest_width, FX_BOOL bFlipX, int clip_left, int clip_width) const;
protected:
	CFX_DIBitmap565* m_pBitmap565;
	FX_LPBYTE m_pCacheScanline;
	FX_INT32 m_Bpp;
	FX_INT32 m_Line;
};

/**
 * @brief A scanline compositer.
 */
class CFX_ScanlineCompositor565 : public CFX_Object
{
public:
	/** The constructor. */
	CFX_ScanlineCompositor565();
	/** The destructor. */
	~CFX_ScanlineCompositor565();

	/**
	 * Initialize the scanline compositor
	 *
	 * @param[in] src_format		The source bitmap format.
	 * @param[in] pSrcPalette		Pointer to source palette, the palette entries whether FX_ARGB or FX_CMYK depending on the source bitmap format.
	 * @param[in] mask_color		The src color to mask. applicable src_format is 1/8bppMask. FX_ARGB or FX_CMYK depending on color type.
	 * @param[in] blend_type		Blend type. FXDIB_BLEND_XXX
	 * @param[in] bClip				The flag indicate the destination scanline is clipping.
	 * @param[in] alpha_flag		The flag indicate color type and alpha value, alpha_flag == (color_type<<8)|alpha
	 *								color type: 0 for rgb, 1 for cmyk
	 * @param[in] pIccTransform		Pointer to the color mapping context for source format to destination if exist.
	 */
	FX_BOOL				Init(FXDIB_Format src_format, FX_DWORD* pSrcPalette, FX_INT32 width, 
							FX_DWORD mask_color, int blend_type, FX_BOOL bClip, FX_BOOL bRgbByteOrder = FALSE, int alpha_flag = 0, void* pIccTransform = NULL);

	/** 
	 * The scanline composite routine, the source format must be Cmyk with bpp > 8
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source cmyk scanline
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] src_extra_alpha	Pointer to source extra alpha scanline if exist(Such as FXDIB_XXXa).
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositeCmykBitmapLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan, 
											FX_LPCBYTE src_extra_alpha);
	
	/** 
	 * The scanline composite routine, the source format must be Rgb with bpp > 8
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source rgb scanline
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] src_extra_alpha	Pointer to source extra alpha scanline if exist(Such as FXDIB_XXXa).
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositeRgbBitmapLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan, 
											FX_LPCBYTE src_extra_alpha = NULL);
	
	/** 
	 * The scanline composite routine, the source format must be 1/8bppPalette(1/8bppRgb(a) or 1/8bppCmyk(a)).
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source palette scanline, if source bitmap without palette, use default gray-scale palette.
	 *								See Init parameter pSrcPalette.
	 * @param[in] src_left			The source scanline column offset, only invalid in 1bpp.
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] src_extra_alpha	Pointer to source extra alpha scanline if exist(Such as FXDIB_XXXa).
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositePalBitmapLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width, FX_LPCBYTE clip_scan, 
											FX_LPCBYTE src_extra_alpha = NULL);
	
	/** 
	 * The scanline composite routine, the source format must be 8bppMask, the source color is determined by mask_color.
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source 8bppMask scanline
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositeByteMaskLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan);
	
	/** 
	 * The scanline composite routine, the source format must be 8bppMask, the source color is determined by mask_color.
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source 1bppMask scanline
	 * @param[in] src_left			The source scanline column offset
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositeBitMaskLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width, FX_LPCBYTE clip_scan);

protected:
	int					m_Transparency;		/**< Compositer selector */
	FXDIB_Format		m_SrcFormat,		/**< The source bitmap format */
						m_DestFormat;		/**< The destination bitmap format */
	FX_DWORD*			m_pSrcPalette;		/**< Can be ARGB palette, gray palette or CMYK palette. */
	
	int					m_MaskAlpha,		/**< Denote the alpha value of mask color. */
						m_MaskRed,			/**< Denote the Red value in RGB, the Cyan value in CMYK and the Gray value in color-scale. */
						m_MaskGreen,		/**< Denote the Green value in RGB, the Magenta value in CMYK. */
						m_MaskBlue,			/**< Denote the Blue value in RGB, the Yellow value in CMYK. */
						m_MaskBlack;		/**< Denote the Key-black value in CMYK. */

	int					m_BlendType;		/**< Blending type */
	void*				m_pIccTransform;	/**< Take the color mapping context for source format to destination. */
	FX_LPBYTE			m_pCacheScanline;	/**< The cache scanline used in transform. */
	int					m_CacheSize;		/**< The cache scanline size. */
	FX_BOOL             m_bRgbByteOrder;
};

/**
 * @brief Bitmap Composer: An implementation of scanline composer which 
 */
class CFX_BitmapComposer565 : public IFX_ScanlineComposer, public CFX_Object
{
public:
	/** The constructor. */
	CFX_BitmapComposer565();
	/** The destructor. */
	~CFX_BitmapComposer565();
	
	/** 
	 * Set the composite destination and parameters.
	 *
	 * @param[in] pDest				Pointer to destination bitmap, the scanline will composite to it,
	 *								Note: BitmapComposer needs the bitmap all the time, so the caller must keep the buffer.
	 * @param[in] pClipRgn			Pointer to clipping region of destination area if exist.
	 * @param[in] bitmap_alpha		Opacity of source bitmap
	 * @param[in] mask_color		The source color if source is an AlphaMask. FX_ARGB or FX_CMYK depending on the color type.
	 * @param[in] dest_rect			The clip rect of destination area.
	 * @param[in] bVertical			Whether need vertical render
	 * @return TRUE for success, FALSE for failure.
	 */
	void				Compose(CFX_DIBitmap565* pDest565, const CFX_ClipRgn* pClipRgn, int bitmap_alpha, 
							FX_DWORD mask_color, FX_RECT& dest_rect, FX_BOOL bVertical, FX_BOOL bFlipX,
							FX_BOOL bFlipY, FX_BOOL bRgbByteOrder = FALSE, 
							int alpha_flag = 0, void* pIccTransform = NULL, int blend_type = FXDIB_BLEND_NORMAL);

	/** 
	 * Init composite parameter.
	 *
	 * @param[in] width				The width of the source bitmap.
	 * @param[in] height			The height of the source bitmap.
	 * @param[in] src_format		The format of the source bitmap.
	 * @param[in] pSrcPalette		Pointer to source palette data to composite to the destination bitmap.
	 * @return TRUE for success, FALSE for failure.
	 */
	virtual FX_BOOL		SetInfo(int width, int height, FXDIB_Format src_format, FX_DWORD* pSrcPalette);
	
	/** 
	 * Compose scanline according to the source input scanline and extra alpha channel scanline.
	 * The composer will select a proper compositer to do compose.
	 *
	 * @param[in] line				The zero-based row index of the source bitmap.
	 * @param[in] scanline			Pointer to source scanline
	 * @param[in] scan_extra_alpha	Pointer to source extra alpha scanline if exist.
	 */
	virtual	void		ComposeScanline(int line, FX_LPCBYTE scanline, FX_LPCBYTE scan_extra_alpha);

protected:
	/** 
	 * Used by ComposeScanline.
	 *
	 * @param[in] dest_scan			Pointer to suitable destination scanline select from destination bitmap, may be vertical.
	 * @param[in] src_scan			Pointer to source scanline is specified by ComposeScanline
	 * @param[in] dest_width		The destination scanline length.
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] src_extra_alpha	Pointer to source extra alpha scanline if exist(Such as FXDIB_XXXa).
	 * @param[in] dst_extra_alpha	Pointer destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				DoCompose(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int dest_width, FX_LPCBYTE clip_scan, 
								FX_LPCBYTE src_extra_alpha = NULL);

	CFX_DIBitmap565*	m_pBitmap565;		/**< The destination bitmap */
	const CFX_ClipRgn*	m_pClipRgn;		/**< The clipping region of destination bitmap. */
	FXDIB_Format		m_SrcFormat;	/**< The source bitmap format. */
	int					m_DestLeft, m_DestTop, m_DestWidth, m_DestHeight, m_BitmapAlpha;
	FX_DWORD			m_MaskColor;
	const CFX_DIBitmap*	m_pClipMask;
	CFX_ScanlineCompositor565	m_Compositor;
	FX_BOOL				m_bVertical, m_bFlipX, m_bFlipY;
	int					m_AlphaFlag;
	void*				m_pIccTransform;
	FX_BOOL             m_bRgbByteOrder;
	int					m_BlendType;

	void				ComposeScanlineV(int line, FX_LPCBYTE scanline, FX_LPCBYTE scan_extra_alpha = NULL);
	FX_LPBYTE			m_pScanlineV, m_pClipScanV, m_pAddClipScan;
};

/** @brief A progressive bitmap rendering engine. */
class CFX_ImageRenderer565 : public CFX_Object
{
public:
	/** The constructor. */
	CFX_ImageRenderer565();
	/** The destructor. */
	~CFX_ImageRenderer565();

	/**
	 * Shortcut for rendering a DIB (colored or mask) with explicit matrix.
	 *
	 * Now this process can be progressive. If Start success, then Continue
	 * should be called to finish the rendering (may need multiple calls).
	 *
	 * @param[in] pDevice			The device gray,mask or colored bitmap.
	 * @param[in] pClipRgb			The clipping region of destination bitmap.
	 * @param[in] pSource			The input colored or mask bitmap.
	 * @param[in] bitmap_alpha		The constant alpha for the bitmap.
	 * @param[in] mask_color		The color to be masked.
	 * @param[in] pMatrix			The matrix used to output the bitmap.
	 * @param[in] dib_flags			The stretching flags.
	 * @param[in] alpha_flag		The flag indicate color type and alpha value, alpha_flag == (color_type<<8)|alpha
	 *								color type: 0 for rgb, 1 for cmyk
	 * @param[in] pIccTransform		The color mapping context for source format(color type describes in alpha_flag) to destination(this bitmap).
	 * @return the status describes in FXDIB_PROGRESSIVE_XXX
	 */
	FX_INT32			Start(CFX_DIBitmap565* pDevice, const CFX_ClipRgn* pClipRgn, 
							const CFX_DIBSource* pSource, int bitmap_alpha,
							FX_DWORD mask_color, const CFX_AffineMatrix* pMatrix, FX_DWORD dib_flags, 
							FX_BOOL bRgbByteOrder = FALSE, int alpha_flag = 0, void* pIccTransform = NULL,
							int blend_type = FXDIB_BLEND_NORMAL);
	/**
	 * Continue rendering.
	 *
	 * @param[in] pPause			The pause interface.
	 * @return the status describes in FXDIB_PROGRESSIVE_XXX
	 */
	FX_INT32			Continue(IFX_Pause* pPause);

protected:
	CFX_DIBitmap565*	m_pDevice;
	const CFX_ClipRgn*	m_pClipRgn;
	int					m_BitmapAlpha;
	FX_DWORD			m_MaskColor;
	CFX_AffineMatrix	m_Matrix;
	CFX_ImageTransformer*	m_pTransformer;
	CFX_ImageStretcher	m_Stretcher;
	CFX_BitmapComposer565	m_Composer;
	int					m_Status;
	int					m_DestLeft, m_DestTop;
	FX_RECT				m_ClipBox;
	FX_DWORD			m_Flags;
	int					m_AlphaFlag;
	void*				m_pIccTransform;
	FX_BOOL				m_bRgbByteOrder;
	int					m_BlendType;
};

//<<<+++OPENSOURCE_MUST_BEGIN
#endif // _FPDF_DIB_H_
//<<<+++OPENSOURCE_MUST_END


/** @} */
